#include "NeoRoller.h"
#include "private/NeoRollerPrivate.h"
#include <QMouseEvent>
#include <QPropertyAnimation>

NEO_PUBLIC_PROPERTY_CREATE_NOTIFY_CPP(NeoRoller, QString, CurrentItem)
NEO_PUBLIC_PROPERTY_CREATE_CPP(NeoRoller, QColor, BackgroundColor)
NEO_PUBLIC_PROPERTY_CREATE_CPP(NeoRoller, QColor, SelectorColor)
NEO_PUBLIC_PROPERTY_CREATE_CPP(NeoRoller, QColor, TextColor)
NEO_PUBLIC_PROPERTY_CREATE_CPP(NeoRoller, QColor, SelectorTextColor)

NeoRoller::NeoRoller(QWidget *parent)
    : QWidget(parent), d_ptr(new NeoRollerPrivate())
{
    NEO_PUBLIC_POINT(NeoRoller)
    d->q_ptr = this;
    connect(d->pOffsetAnimation, &QPropertyAnimation::valueChanged, this, [this]()
            { this->update(); });
    connect(d->pOffsetAnimation, &QPropertyAnimation::finished, this, [this]()
            { 
                NEO_PUBLIC_POINT(NeoRoller)
                d->pCurrentIndex = d->pNextIndex;
                emit neoCurrentItemChanged(); });
}

NeoRoller::~NeoRoller() = default;

void NeoRoller::setItems(const QStringList &items)
{
    NEO_PUBLIC_POINT(NeoRoller)
    d->pItems = std::move(items);
}

QStringList NeoRoller::getItems() const noexcept
{
    NEO_PUBLIC_POINT(const NeoRoller)
    return d->pItems;
}

void NeoRoller::setMaxVisibleItems(int count)
{
    NEO_PUBLIC_POINT(NeoRoller)
    if ((count & 1) == 0)
    {
        qWarning() << "MaxVisibleItems must be an odd number.";
        return;
    }
    else if (count < 1)
    {
        qWarning() << "MaxVisibleItems must be greater than 0.";
        return;
    }
    d->pMaxVisibleItems = count;
}

int NeoRoller::getMaxVisibleItems() const
{
    NEO_PUBLIC_POINT(const NeoRoller)
    return d->pMaxVisibleItems;
}

void NeoRoller::paintEvent(QPaintEvent *event)
{
    NEO_PUBLIC_POINT(NeoRoller)
    NEO_PAINTER_RESET
    d->drawBackground(&painter);
    d->drawSelector(&painter);
    d->drawItems(&painter);
}

void NeoRoller::mousePressEvent(QMouseEvent *event)
{
    NEO_PUBLIC_POINT(NeoRoller)
    if (event->button() == Qt::LeftButton)
    {
        QPoint pos = event->pos();
        QRect adjustedRect = this->rect().adjusted(NEO_RADIUS_ADJUSTED_VALUES);
        int index = (pos.y() - adjustedRect.top()) * d->pMaxVisibleItems / adjustedRect.height() + d->pCurrentIndex - d->pMaxVisibleItems / 2;
        index = (index + d->pItems.size()) % d->pItems.size();
        d->updateCurrentItem(index, pos.y() > adjustedRect.center().y());
        event->accept();
        return;
    }
    return QWidget::mousePressEvent(event);
}

void NeoRoller::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        event->accept();
        return;
    }
    return QWidget::mouseReleaseEvent(event);
}

void NeoRoller::wheelEvent(QWheelEvent *event)
{
    NEO_PUBLIC_POINT(NeoRoller)
    if (event->angleDelta().y() != 0)
    {
        int steps = event->angleDelta().y() / 50;
        int newIndex = (d->pCurrentIndex + steps + d->pItems.size()) % d->pItems.size();
        d->updateCurrentItem(newIndex, steps > 0);
        event->accept();
        return;
    }
    return QWidget::wheelEvent(event);
}

void NeoRoller::resizeEvent(QResizeEvent *event)
{
    NEO_PUBLIC_POINT(NeoRoller)
    d->updateWidgetGeometry(event->size());
    return QWidget::resizeEvent(event);
}